2012-10-18 18 views
21

W jaki sposób python rozróżnia atrybut klasy, atrybut instancji i metodę, gdy nazwy są takie same?python: Co się dzieje, gdy atrybut class, atrybut instance i method mają taką samą nazwę?

class Exam(object): 

    test = "class var" 

    def __init__(self, n): 
     self.test = n 

    def test(self): 
     print "method : ",self.test 

test_o = Exam("Fine") 

print dir(test_o) 

print Exam.test 
print test_o.test 
test_o.test() 

wyjściowa:

['__class__', '__delattr__', '__dict__', '__doc__', '__format__', '__getattribute__', '__hash__', '__init__', '__module__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'test'] 
<unbound method load.test> 
Fine 
Traceback (most recent call last): 
    File "example.py", line 32, in <module> 
    test_o.test() 
TypeError: 'str' object is not callable 

Jak wywołać

  1. atrybut klasy, Exam.test -><unbound method load.test> wyjście pokazuje metodę
  2. instancji atrybut test_o.test ->"Fine"
  3. metody test_o.test() ->TypeError: 'str' object is not callable

Odpowiedz

2

Możesz napisać

Exam.test(test_o) 

lub

Exam.test.__get__(test_o)() 

W tym ostatnim przypadku jesteś wykorzystując fakt, że metody są descriptors do konwersji <unbound method load.test> Do bound metoda, dzięki czemu można go wywołać za pomocą pojedynczych nawiasów.

Podczas pisania test_o.test(), Python nie wie, że próbujesz wywołać metodę; możesz próbować wywołać funkcję lub obiekt wywoływalny, który został zainstalowany na obiekcie jako element danych instancji. Zamiast tego wyszukuje atrybut test, najpierw na obiekcie, a następnie na jego klasie, ale ponieważ atrybut istnieje na obiekcie, ukrywa on metodę na klasie.

Człon klasa

test = "class var" 

nie jest dostępny (w rzeczywistości nie istnieje nigdzie), ponieważ są zastępowane metodą test; kiedy wykonywany jest kod class statement, jego przestrzeń nazw jest gromadzona w dyktafonie przed przekazaniem do jego metaklasy, a późniejsze nazwy zastępują wcześniejsze.

+0

co się stało z wywołaniem test_o.test()? – naren

+0

@naren próbujesz wywołać członka instancji; patrz wyżej. – ecatmur

1

można wywołać metody jako metody klasy i przekazać swoje wystąpienie do niego:

Exam.test(test_o) 

Lub, jeśli nie chcesz wykorzystania Exam:

type(test_o).test(test_o) 
17

atrybuty klasy są dostępne za pośrednictwem klasy :

YourClass.clsattribute 

lub przez instancję (jeśli instancja nie została przesłonięta Ritten atrybut klasy)

instance.clsattribute 

metod, jak podano by ecatmur in his answer są opisowych i są atrybutami klas.

Jeśli uzyskasz dostęp do metody poprzez instancję, to instancja jest przekazywana jako deskryptor jako parametr self. Jeśli chcesz wywołać metodę z klasy, musisz jawnie przekazać instancję jako pierwszy argument. Więc to są równoważne:

instance.method() 
MyClass.method(instance) 

Stosując tę ​​samą nazwę atrybutu instancji oraz sposobu uczyni sposób ukryty za pośrednictwem instancji, ale metoda jest nadal dostępna za pośrednictwem klasy:

#python3 
>>> class C: 
...  def __init__(self): 
...   self.a = 1 
...  def a(self): 
...   print('hello') 
... 
>>> C.a 
<function a at 0x7f2c46ce3c88> 
>>> instance = C() 
>>> instance.a 
1 
>>> C.a(instance) 
hello 

Wnioski : nie podawaj tej samej nazwy atrybutom i metodom instancji. Unikałem tego, podając konkretne nazwy. Metody to akcje, więc zwykle używam dla nich czasowników lub zdań. Atrybuty są danymi, więc używam dla nich rzeczowników/przymiotników, co pozwala uniknąć używania tych samych nazw dla obu metod i atrybutów.

Zauważ, że po prostu nie możesz mieć atrybutu klasy o tej samej nazwie co metoda, ponieważ metoda całkowicie go zastąpi (ostatecznie metody to tylko atrybuty klas, które można wywoływać i automatycznie otrzymują instancję klasy jako pierwszy atrybut).

0

Jak wywołać
atrybut klasy, Exam.test

Nie można, ponieważ podczas wykonywania def test(self) nazwa test jest związany ze sposobem w klasie i odniesienie do "class var" jest stracone.

instancja atrybutu test_o.test -> "fine"

już to zrobiłeś.

metoda test_o.test()

nie można nazwać w ten sposób, ponieważ podczas wykonywania self.test = n nazwa test jest zobowiązany do tego, co obiekt n odwołań w instancji oraz odniesienie do metody w instancji jest stracone .

Ale jak wskazano w innych odpowiedzi można wywołać metodę w klasie i przekazać instancję do niego: Exam.test(test_o)