Всичко в 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()