Всичко в Python е обект. Това включва:
type()
и dir()
dir()
ни позволява да видим атрибутите, на които един метод отговаря. type()
пък ни връща класът на своя аргумент като обект.
text = ["Ni!", "Shrubbery", "Knights"] print(type(text), tupe(text) == tuple) print(dir(text))
Всъщност, представете си следното.
.
__dict__
..
те се търсят в този речник. Ако не бъдат намерени се извиква __getattr__
в случай че е дефиниран.class Foo(object): pass f = Foo() f.spam, f.eggs = "Spam", "Eggs" print("f.__dict__:", f.__dict__) print("f.spam, f.eggs:", f.spam, f.eggs) f.__dict__ = {'larodi' : "Larodi"} print("f.larodi: " + f.larodi) print("f.spam: " + f.spam)
Всъщност, нещата са една идея по-сложни.
__class__
. Последния също е обект.obj.name
се изпълнява функцията __getattribute__(obj, name)
на obj.__class__
.object
. Тя е имплементирана както обяснихме два слайда по-рано.Полежението при класовете е идентично. Просто имате по-интересен синтаксис за дефиниране на __dict__
.
class Foo(object): spam = "Eggs" def bar(self): pass print(Foo.__dict__.keys())
При извикване на obj.name
:
name
не присъства в obj.__dict__
. Ако да - връща се тази стойностobj.__class__
има такъв атрибут в своя __dict__
. Ако да, и той няма метод __get__
, се връщаobj.__dict__
има метод __get__
, то методът obj.__dict__.__get__
се изпълнява със съответните оргументиclass Person(object): def __init__(self, name): self.name = name def sayHi(self): print("Hi, I am", self.name) def wave(self): print(self.name, "is waving") mityo = Person("Mityo") print(mityo.sayHi) print(Person.sayHi) mityo.sayHi() Person.sayHi(mityo)
class Person(object): def __init__(self, name): self.name = name def sayHi(self): print("Hi, I am", self.name) def wave(self): print(self.name, "is waving") class Hacker(object): def sayHi(self): print(self.name, "has been hacked by ninjas") def slash(self): print("Slash! Slash! Slash!") mityo = Person("Mityo") mityo.sayHi() mityo.wave() mityo.__class__ = Hacker mityo.sayHi() mityo.slash() mityo.wave()
type()
revisitedМоже да разглеждате type
и като конструктор за нови класове. Следните дефиниции са еквивалентни:
class Base(object): pass class Derived(Base): count = 0 def foo(self): return "The foo of %s" % self Derived = type("Derived", (Base,), { 'count': 0, 'foo': lambda self: "The foo of %s" % self })
Всъщност, всички класове дефинирани с class
са инстанции на type
.
[Metaclasses] are deeper magic than 99% of the users should ever worry about. If you wonder whether you need them, you don't (the people who actually need them know with certainty that they need them, and don't need an explanation about why).
— Tim Peters
Всеки клас е инстанция или на type
, или на друг тип, който го наследява. Това се нарича „клас на класа“ или „метаклас“.
Meta (from Greek: after, beyound, with) is a prefix used in English in order to indicate a concept which is an abstraction from another concept, used to complete or add to the latter.
Определянето на метакласа става така:
class Foo(object, metaclass=type): pass class BarMeta(type): pass class Bar(object, metaclass=BarMeta): pass
Обекта поставен в metaclass
трябва да дефинира оператор ()
, вземащ три аргументи - име на клас, n-орка от родители и речник с атрибути. Трябва да връща нов клас на базата на тези аргументи (така прави type
). Съответно, може или да си направите наследник на type
или да дадете функция с такава сигнатура.
import re def Namer(clname, bases, cdict): for name in [_ for _ in cdict.keys() if re.search('[a-z][A-Z]', _)]: new_name = re.sub('([a-z])([A-Z])', r'\1_\2', name).lower() cdict[new_name] = cdict[name] del cdict[name] return type(clname, bases, cdict) class Person(object, metaclass=Namer): theNumberOfPersons = 1 def __init__(self, name): self.name = name def getMyNameNow(self): return self.name p = Person("Mityo") print(p.get_my_name_now()) print(Person.the_number_of_persons) print(p.getMyNameNow())
def without_ego(func): def wrapped(self, *args, **kwargs): old_self = func.__globals__.get('self') func.__globals__['self'] = self result = func(*args, **kwargs) func.__globals__['self'] = old_self return result wrapped.__name__ = func.__name__ return wrapped class selfless(type): def __new__(cls, name, bases, attrs): for key, value in attrs.items(): if not hasattr(value, '__call__'): continue attrs[key] = without_ego(value) return type.__new__(cls, name, bases, attrs) class Person(metaclass=selfless): def __init__(name): self.name = name def sayHi(): print("Hi, I am", self.name) Person("Mityo").sayHi()